﻿using H.RT;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;

namespace H.Runtime.Host
{
    /// <summary>
    /// 应用程序域管理器
    /// </summary>
    public class DomainManager : MarshalByRefObject
    {
        private const string HDM_ID = "HDM_ID";
        private const string HRT_DOMAINMANAGER = "HRT_DOAMIN_MANAGER";

        /// <summary>
        /// 下一个可以用于分配的ID
        /// </summary>
        private static int _NextID = 1000;

        /// <summary>
        /// 域管理字典
        /// </summary>
        private readonly Dictionary<int, AppDomain> DomainDict = new Dictionary<int, AppDomain>();

        /// <summary>
        /// 初始化一个域管理器
        /// </summary>
        public DomainManager()
        {
        }

        /// <summary>
        /// 获取正在运行的APP的信息
        /// </summary>
        /// <returns></returns>
        public KeyValuePair<int, string>[] GetRunningApp()
        {
            return (from kv in DomainDict select new KeyValuePair<int, string>(kv.Key, kv.Value.FriendlyName)).ToArray();
        }

        /// <summary>
        /// 创建一个新的应用程序域,并纳入管理
        /// </summary>
        /// <param name="name"></param>
        /// <param name="newID"></param>
        /// <returns></returns>
        public AppDomain CreateDomain(string name, out int newID)
        {
            AppDomain appDomain = HDomain.CreateDomain(name);
            int id = _NextID++;
            appDomain.SetData(HDM_ID, id);
            appDomain.SetData(HRT_DOMAINMANAGER, this);
            appDomain.DomainUnload += AppDomain_DomainUnload;
            DomainDict.Add(id, appDomain);
            newID = id;
            return appDomain;
        }

        private static void AppDomain_DomainUnload(object sender, EventArgs e)
        {
            if (AppDomain.CurrentDomain.GetData(HRT_DOMAINMANAGER) is DomainManager manager)
            {
                try
                {
                    manager.UnregisteredDomain((int)AppDomain.CurrentDomain.GetData(HDM_ID));
                }
                catch (Exception)
                {
           
                }
            }
        }

        /// <summary>
        /// 将一个应用程序域从任务列表中删除(此函数给AppDomain_DomainUnload使用,请不要滥用它)
        /// </summary>
        /// <param name="domainID"></param>
        /// <returns></returns>
        public bool UnregisteredDomain(int domainID)
        {
            return DomainDict.Remove(domainID);
        }

        /// <summary>
        /// 卸载一个应用程序域
        /// </summary>
        /// <param name="domainID"></param>
        public bool UnloadDomain(int domainID)
        {
            try
            {
                if (DomainDict.TryGetValue(domainID, out AppDomain appDomain))
                {
                    AppDomain.Unload(appDomain);
                    return true;
                }
                else
                {
                    return false;
                }
            }
            catch (Exception)
            {
                return false;
            }
        }
    }
}
